// PhoneDeviceManage.exe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "SvcCommon.h"
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include "SvcMessages.h"

//#include "sample.h"



SERVICE_STATUS          g_SvcStatus; 
SERVICE_STATUS_HANDLE   g_SvcStatusHandle; 
HANDLE                  g_hSvcStopEvent = NULL;

int SvcInstall(void);
VOID WINAPI SvcCtrlHandler( DWORD ); 
VOID WINAPI SvcMain( DWORD, LPTSTR * ); 

VOID ReportSvcStatus( DWORD, DWORD, DWORD );
VOID SvcInit( DWORD, LPTSTR * ); 
VOID SvcReportEvent( LPTSTR );

int _tmain(int argc, _TCHAR* argv[])
{
	// If command-line parameter is "install", install the service. 
	// Otherwise, the service is probably being started by the SCM.
	int iErrCode = 0;
	if( lstrcmpi( argv[1], TEXT("install")) == 0 )
	{
		iErrCode = SvcInstall();
		return iErrCode;
	}

	// we can add any additional services for the process to this table.
	SERVICE_TABLE_ENTRY DispatchTable[] = 
	{ 
		{ (LPTSTR)g_pServiceName, (LPSERVICE_MAIN_FUNCTION) SvcMain }, 
		{ NULL, NULL } 
	}; 

	// This call returns when the service has stopped. 
	// The process should simply terminate when the call returns.
	if (!StartServiceCtrlDispatcher( DispatchTable )) 
	{ 
		iErrCode = GetLastError();
		SvcReportEvent(TEXT("StartServiceCtrlDispatcher")); 
	} 
	return iErrCode;
}

int SvcInstall()
{
	SC_HANDLE schSCManager;
	SC_HANDLE schService;
	TCHAR szPath[MAX_PATH];
	int iLastErr = 0;

	if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
	{
		iLastErr = GetLastError();
		printf("Cannot install service (%d)\n", iLastErr);
		return iLastErr;
	}

	// Get a handle to the SCM database. 
	schSCManager = OpenSCManager(NULL, NULL,SC_MANAGER_ALL_ACCESS);  
	if (NULL == schSCManager) 
	{
		iLastErr = GetLastError();
		printf("OpenSCManager failed (%d)\n", iLastErr);
		return iLastErr;
	}

	// Create the service
	schService = CreateService( 
		schSCManager,              // SCM database 
		g_pServiceName,                   // name of service 
		g_pServiceName,                   // service name to display 
		SERVICE_ALL_ACCESS,        // desired access 
		SERVICE_WIN32_OWN_PROCESS, // service type 
		SERVICE_DEMAND_START,      // start type 
		SERVICE_ERROR_NORMAL,      // error control type 
		szPath,                    // path to service's binary 
		NULL,                      // no load ordering group 
		NULL,                      // no tag identifier 
		NULL,                      // no dependencies 
		NULL,                      // LocalSystem account 
		NULL);                     // no password 

	if (schService == NULL) 
	{
		iLastErr = GetLastError();
		printf("CreateService failed (%d)\n", iLastErr); 

		CloseServiceHandle(schSCManager);
		return iLastErr;
	}
	else 
	{
		printf("Service installed successfully\n");
	}

	CloseServiceHandle(schService); 
	CloseServiceHandle(schSCManager);
	return iLastErr;
}

//
// Purpose: 
//   Entry point for the service
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None.
//
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
	// Register the handler function for the service.
	g_SvcStatusHandle = RegisterServiceCtrlHandler( 
		g_pServiceName, 
		SvcCtrlHandler);

	if( !g_SvcStatusHandle )
	{ 
		SvcReportEvent(TEXT("RegisterServiceCtrlHandler Fail.")); 
		return; 
	} 

	g_SvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
	g_SvcStatus.dwServiceSpecificExitCode = 0;    

	// Report initial status to the SCM
	ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

	// Perform service-specific initialization and work.
	SvcInit( dwArgc, lpszArgv );
}

//
// Purpose: 
//   The service code
//
// Parameters:
//   dwArgc - Number of arguments in the lpszArgv array
//   lpszArgv - Array of strings. The first string is the name of
//     the service and subsequent strings are passed by the process
//     that called the StartService function to start the service.
// 
// Return value:
//   None
//
VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)
{
	// TO_DO: Declare and set any required variables.
	//   Be sure to periodically call ReportSvcStatus() with 
	//   SERVICE_START_PENDING. If initialization fails, call
	//   ReportSvcStatus with SERVICE_STOPPED.

	// Create an event. The control handler function, SvcCtrlHandler signals this event when it receives the stop control code.

	g_hSvcStopEvent = CreateEvent(
		NULL,    // default security attributes
		TRUE,    // manual reset event
		FALSE,   // not signaled
		NULL);   // no name

	if ( g_hSvcStopEvent == NULL)
	{
		ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
		return;
	}
	// Report running status when initialization is complete.
	ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

	// TO_DO: Perform work until service stops.

	while(1)
	{
		// Check whether to stop the service.
		WaitForSingleObject(g_hSvcStopEvent, INFINITE);
		ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
		return;
	}
}

//
// Purpose: 
//   Sets the current service status and reports it to the SCM.
//
// Parameters:
//   dwCurrentState - The current state (see SERVICE_STATUS)
//   dwWin32ExitCode - The system error code
//   dwWaitHint - Estimated time for pending operation, 
//     in milliseconds
// 
// Return value:
//   None
//
VOID ReportSvcStatus( DWORD dwCurrentState,
					 DWORD dwWin32ExitCode,
					 DWORD dwWaitHint)
{
	static DWORD dwCheckPoint = 1;

	// Fill in the SERVICE_STATUS structure.
	g_SvcStatus.dwCurrentState = dwCurrentState;
	g_SvcStatus.dwWin32ExitCode = dwWin32ExitCode;
	g_SvcStatus.dwWaitHint = dwWaitHint;

	if (dwCurrentState == SERVICE_START_PENDING)
	{
		g_SvcStatus.dwControlsAccepted = 0;
	}
	else 
	{
		g_SvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
	}

	if ((dwCurrentState == SERVICE_RUNNING) ||	(dwCurrentState == SERVICE_STOPPED))
	{
		g_SvcStatus.dwCheckPoint = 0;
	}
	else 
	{
		g_SvcStatus.dwCheckPoint = dwCheckPoint++;
	}

	// Report the status of the service to the SCM.
	SetServiceStatus( g_SvcStatusHandle, &g_SvcStatus );
}

//
// Purpose: 
//   Called by SCM whenever a control code is sent to the service
//   using the ControlService function.
//
// Parameters:
//   dwCtrl - control code
// 
// Return value:
//   None
//
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
	// Handle the requested control code. 

	switch(dwCtrl) 
	{  
	case SERVICE_CONTROL_STOP: 
		ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);

		// Signal the service to stop.

		SetEvent(g_hSvcStopEvent);

		return;

	case SERVICE_CONTROL_INTERROGATE: 
		// Fall through to send current status.
		break; 

	default: 
		break;
	} 

	ReportSvcStatus(g_SvcStatus.dwCurrentState, NO_ERROR, 0);
}

//
// Purpose: 
//   Logs messages to the event log
//
// Parameters:
//   szFunction - name of function that failed
// 
// Return value:
//   None
//
// Remarks:
//   The service must have an entry in the Application event log.
//
VOID SvcReportEvent(LPTSTR szFunction) 
{ 
	HANDLE hEventSource;
	LPCTSTR lpszStrings[2];
	TCHAR Buffer[80];

	hEventSource = RegisterEventSource(NULL, g_pServiceName);

	if( NULL != hEventSource )
	{
		StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());

		lpszStrings[0] = g_pServiceName;
		lpszStrings[1] = Buffer;

		ReportEvent(hEventSource,        // event log handle
			EVENTLOG_ERROR_TYPE, // event type
			0,                   // event category
			SVC_ERROR,           // event identifier
			NULL,                // no security identifier
			2,                   // size of lpszStrings array
			0,                   // no binary data
			lpszStrings,         // array of strings
			NULL);               // no binary data

		DeregisterEventSource(hEventSource);
	}
}





